package cn.jnetty.remoting;
import cn.jnetty.api.JnettyProperties;
import cn.jnetty.api.JnettyHandler;
import cn.jnetty.api.JnettyServer;
import cn.jnetty.api.annotation.JAutowired;
import cn.jnetty.api.exception.JnettyRomotingException;
import cn.jnetty.remoting.code.JnettyCodecAdapter;
import cn.jnetty.remoting.code.JnettyCodecAdapterImpl;
import cn.jnetty.remoting.platform.JnettyPlatform;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
/**
 * @author 猪哥亮
 * @email 1030681978@qq.com
 * @date 2020/4/2 17:08
 * 描述：
 */
public abstract class AbstractJnettyServer implements JnettyServer {
    protected final JnettyPlatform jnettyPlatform;
    protected final Logger log = LoggerFactory.getLogger(AbstractJnettyServer.class);
    protected EventLoopGroup bossGroup;
    protected EventLoopGroup workerGroup;
    protected ServerBootstrap bootstrap;
    @JAutowired(required = false)
    protected JnettyProperties configuration;
    @JAutowired(required = false)
    protected JnettyHandler handler;
    protected int port;
    public AbstractJnettyServer() {
        this.jnettyPlatform = new JnettyPlatform();
    }
    protected void initJnettyConfig(){
        if(configuration == null){
            configuration = new JnettyProperties();
        }
        this.bootstrap = new ServerBootstrap();
        this.bossGroup = this.jnettyPlatform.getJnettyMultithreadEventLoopGroup(configuration.getBossGroup(),null);
        this.workerGroup = this.jnettyPlatform.getJnettyMultithreadEventLoopGroup(configuration.getWorkerGroup(),new JnettyThreadFactory(configuration.getThreadFactoryName()));
        this.bootstrap.group(this.bossGroup, this.workerGroup).channel(this.jnettyPlatform.getJnettyServerSocketChannel());
        // Socket参数，地址复用，默认值false
        this.bootstrap.option(ChannelOption.SO_REUSEADDR, true);
        // Socket参数，服务端接受连接的队列长度，如果队列已满，客户端连接将被拒绝。默认值，Windows为200，其他为128。
        this.bootstrap.option(ChannelOption.SO_BACKLOG, configuration.getOptionLength());
    }

    public int getMaxContentLength() {
        return configuration.getMaxContentLength();
    }

    @Override
    public void startup() {
        try {
            if (port <= 0) {
                log.info(configuration.getServerType() + "服務器启动失败，绑定的端口号不能为0。");
                throw new JnettyRomotingException("{0}服務器启动失败，绑定的端口号不能为0。",configuration.getServerType());
            }
            log.info(configuration.getServerType() + "服务器启动，绑定端口####################" +  port);
            // linux系统下使用SO_REUSEPORT特性，使得多个线程绑定同一个端口
            int cpuNum = 1;
            if(this.jnettyPlatform.isEpoll()){
                cpuNum = Runtime.getRuntime().availableProcessors();
            }
            for (int i = 0; i < cpuNum; i++) {
                this.bootstrap.bind(port).sync();
            }
            log.info(configuration.getServerType() + "服务器启动成功.端口綁定>>>>>>>>>>>>" + port);
        } catch (Exception e) {
            throw new JnettyRomotingException("{0}服務器启动失败，绑定的端口号不能为{1}。",e,configuration.getServerType(),port);
        }
    }
    /**
     * 停止服务时存储数据最大等待时间，单位：分钟
     */
    @Override
    public void shutdown() {
        Future<?> boosFuture = bossGroup.shutdownGracefully();
        Future<?> workFuture = workerGroup.shutdownGracefully();
        try {
            if (boosFuture.await(configuration.getShutdownMaxTime(), TimeUnit.MINUTES)) {
                log.info(configuration.getServerType() + "NettyBoss关闭成功.");
            }
            if (workFuture.await(configuration.getShutdownMaxTime(), TimeUnit.MINUTES)) {
                log.info(configuration.getServerType() + "NettyWork关闭成功.");
            }
        } catch (InterruptedException ie) {
            log.info(configuration.getServerType() + "关闭网络时发生异常.");
            ie.printStackTrace();
        }
    }
}
